﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// Structure for a complex number
    /// </summary>
    public struct Complex
    {
        #region Data
        /// <summary>
        /// Real part of complex
        /// </summary>
        public double real;
        /// <summary>
        /// Imaginary part of complex
        /// </summary>
        public double imag;
        #endregion

        #region Constructors
        /// <summary>
        /// Initialise une nouvelle instance de la structure <see cref="Complex"/>
        /// </summary>
        /// <param name="real">Partie réelle</param>
        /// <param name="imag">Partie imaginaire</param>
        public Complex(double real, double imag)
        {
            this.real = real;
            this.imag = imag;
        }
        #endregion

        #region Public Members
        /// <summary>
        /// Obtient le module du <see cref="Complex"/>
        /// </summary>
        /// <returns>Retourne le module du <see cref="Complex"/></returns>
        public double Magnitude()
        {
            return (Math.Sqrt(real * real + imag * imag));
        }

        /// <summary>
        /// Obtient le module au carré du <see cref="Complex"/>
        /// </summary>
        /// <returns>Retourne le module au carré du <see cref="Complex"/></returns>
        public double MagnitudeSquared()
        {
            return real * real + imag * imag;
        }

        /// <summary>
        /// Obtient l'argument au carré du <see cref="Complex"/>
        /// </summary>
        /// <returns>Retourne l'argument du <see cref="Complex"/></returns>
        public double Phase()
        {            
            return (Math.Atan(imag / real));
        }
    
        /// <summary>
        /// Obtient le conjugé du <see cref="Complex"/>
        /// </summary>
        /// <returns>Retourne le conjugé du <see cref="Complex"/></returns>
	    public Complex Conjugate()
	    {
		    return new Complex(real, -imag);
	    }

        /// <summary>
        /// Obtient la norme du <see cref="Complex"/>
        /// </summary>
        /// <returns>Retourne la norme du <see cref="Complex"/></returns>
        public double Normalize()
	    {
		    return real * real + imag * imag;
	    }
        #endregion

        #region Object Overrides
        /// <summary>
        /// Retourne une valeur sous forme de <see cref="System.String"/> représentant l'instance actuelle
        /// </summary>
        /// <returns>Retourne une valeur sous forme de <see cref="System.String"/> représentant l'instance actuelle</returns>
        public override string ToString()
        {
            return real + ";" + imag;
        }

        /// <summary>
        /// Indique si cette instance et un object spécifie sont égaux
        /// </summary>
        /// <param name="obj">Object à comparer</param>
        /// <returns>Retourne true si les objets sont égaux ; sinon false.</returns>
        public override bool Equals(object obj)
        {
            if (!(obj is Complex))
                return false;
            Complex y = (Complex)obj;
            return this.real == y.real && this.imag == y.imag;
        }

        /// <summary>
        /// Retourne le code de hachage pour cette instance
        /// </summary>
        /// <returns>Retourne le code de hachage pour cette instance</returns>
        public override int GetHashCode()
        {
            return (int)(real + imag);
        }
        #endregion

        #region Operator Overloads
        /// <summary>
        /// Additionne deux <see cref="Complex"/>
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à additionner</param>
        /// <param name="complex2"><see cref="Complex"/> additionné</param>
        /// <returns>Retourne le somme des deux <see cref="Complex"/></returns>
        public static Complex operator +(Complex complex1, Complex complex2) 
        {
		    return new Complex(complex1.real + complex2.real, complex1.imag + complex2.imag);
        }

        /// <summary>
        /// Soustrait deux <see cref="Complex"/>
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à soustraire</param>
        /// <param name="complex2"><see cref="Complex"/> soustrait</param>
        /// <returns>Retourne le différence des deux <see cref="Complex"/></returns>
	    public static Complex operator -(Complex complex1, Complex complex2)
	    {
            return new Complex(complex1.real - complex2.real, complex1.imag - complex2.imag);
	    }

        /// <summary>
        /// Multiplie deux <see cref="Complex"/>
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à multiplier</param>
        /// <param name="complex2"><see cref="Complex"/> multiplié</param>
        /// <returns>Retourne le produit des deux <see cref="Complex"/></returns>
	    public static Complex operator *(Complex complex1, Complex complex2)
	    {
		    return new Complex(complex1.real * complex2.real - complex1.imag * complex2.imag, complex1.real * complex2.imag + complex1.imag * complex2.real);
	    }

        /// <summary>
        /// Divise deux <see cref="Complex"/>
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à divise</param>
        /// <param name="complex2"><see cref="Complex"/> divisé</param>
        /// <returns>Retourne la division des deux <see cref="Complex"/></returns>
	    public static Complex operator /(Complex complex1, Complex complex2)
	    {
		    double denominator = complex2.real * complex2.real + complex2.imag * complex2.imag;
		    return new Complex((complex1.real * complex2.real + complex1.imag * complex2.imag) / denominator,
                (complex1.imag * complex2.real - complex1.real * complex2.imag) / denominator);
	    }
        
        /// <summary>
        /// Incrémente la partie réelle d'un complexe
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à incrémenter</param>
        /// <returns><see cref="Complex"/> incrémenté</returns>
        public static Complex operator ++(Complex complex1)
        {
            complex1.real++;
            return complex1;
        }

        /// <summary>
        /// Décrémente la partie réelle d'un complexe
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à décrémenter</param>
        /// <returns><see cref="Complex"/> décrémenté</returns>
        public static Complex operator --(Complex complex1)
        {
            complex1.real--;
            return complex1;
        }

        /// <summary>
        /// Ajoute un Double à la partie réelle d'un <see cref="Complex"/>
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/><see cref="Complex"/> à additionner</param>
        /// <param name="val">Double à ajouter à la partie réelle du <see cref="Complex"/></param>
        /// <returns>Retourne le <see cref="Complex"/> additionné</returns>
	    public static Complex operator +(Complex complex1, double val)
	    {
		    return new Complex(complex1.real + val, complex1.imag);
	    }

        /// <summary>
        /// Soustrait un Double à la partie réelle d'un <see cref="Complex"/>
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/><see cref="Complex"/> à soustraire</param>
        /// <param name="val">Double à soustraire de la partie réelle du <see cref="Complex"/></param>
        /// <returns>Retourne le <see cref="Complex"/> soustrait.</returns>
	    public static Complex operator- (Complex complex1, double val)
	    {
		    return new Complex(complex1.real - val, complex1.imag);
	    }

        /// <summary>
        /// Multiplie un <see cref="Complex"/> par un Double
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/><see cref="Complex"/> à multiplier</param>
        /// <param name="val">Coefficient multiplicateur</param>
        /// <returns>Retourne le <see cref="Complex"/> multiplié</returns>
	    public static Complex operator *(Complex complex1, double val)
	    {
		    return new Complex(complex1.real * val, complex1.imag * val);
	    }

        /// <summary>
        /// Divise un <see cref="Complex"/> par un Double
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/><see cref="Complex"/> à diviser</param>
        /// <param name="val">Dénominateur de la division<see cref="Complex"/></param>
        /// <returns>Retourne le <see cref="Complex"/> divisé</returns>
	    public static Complex operator /(Complex complex1, double val)
	    {
		    return new Complex(complex1.real / val, complex1.imag / val);
	    }

        /// <summary>
        /// Teste si deux <see cref="Complex"/> sont égaux
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à comparer</param>
        /// <param name="complex2"><see cref="Complex"/> comparé</param>
        /// <returns>Retourne true si les <see cref="Complex"/> sont égaux ; sinon false.</returns>
	    public static bool operator ==(Complex complex1, Complex complex2)
	    {
		    return complex1.real == complex2.real && complex1.imag == complex2.imag;
	    }

        /// <summary>
        /// Teste si deux <see cref="Complex"/> sont différents
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à comparer</param>
        /// <param name="complex2"><see cref="Complex"/> comparé</param>
        /// <returns>Retourne true si les <see cref="Complex"/> sont différents ; sinon false.</returns>
	    public static bool operator !=(Complex complex1, Complex complex2)
	    {
		    return complex1.real != complex2.real || complex1.imag != complex2.imag;
	    }

        /// <summary>
        /// Test l'égalité entre la partie réelle d'un complexe et un Double
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à comparer</param>
        /// <param name="val">Double à comparer</param>
        /// <returns>Retourne true si la partie réelle du <see cref="Complex"/> et le Double sont égaux ; sinon false.</returns>
	    public static bool operator ==(Complex complex1, double val)
	    {
		    return complex1.real == val && complex1.imag == 0.0;
	    }

        /// <summary>
        /// Teste la différence entre la partie réelle d'un complexe et un Double
        /// </summary>
        /// <param name="complex1"><see cref="Complex"/> à comparer</param>
        /// <param name="val">Double à comparer</param>
        /// <returns>Retourne true si la partie réelle du <see cref="Complex"/> et le Double sont différent ; sinon false.</returns>
	    public static bool operator !=(Complex complex1, double val)
	    {
		    return complex1.real != val || complex1.imag != 0.0;
        }
        #endregion
    }
}
